package com.josn.messagewall.utils;

import org.springframework.stereotype.Component;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * 雪花算法工具类 (单机版)
 * 结构：1位符号位 + 41位时间戳 + 5位数据中心ID + 5位机器ID + 12位序列号
 * 总共64位，对应Java的long类型
 */
@Component
public class GenerateSnowidUtil {
    private static final Logger log = LoggerFactory.getLogger(GenerateSnowidUtil.class);

    private final long twepoch = 1577836800000L;
    private final long workerIdBits = 5L;
    private final long datacenterIdBits = 5L;
    private final long sequenceBits = 12L;
    private final long workerIdShift = sequenceBits;
    private final long datacenterIdShift = sequenceBits + workerIdBits;
    private final long timestampLeftShift = sequenceBits + workerIdBits + datacenterIdBits;
    private final long sequenceMask = -1L ^ (-1L << sequenceBits);
    private final long workerId = 1L;       // 工作机器ID (单机部署，直接写死)
    private final long datacenterId = 1L;   // 数据中心ID (单机部署，直接写死)
    private long sequence = 0L;         // 毫秒内序列
    private long lastTimestamp = -1L;   // 上次生成ID的时间戳

    //构造函数 (修改部分)
    public GenerateSnowidUtil() {
        // 由于 workerId 和 datacenterId 已经是常量，这里不再需要参数校验
        log.info("SnowflakeIdWorker initialized as Spring Bean. WorkerId: {}, DatacenterId: {}", workerId, datacenterId);
    }

    public synchronized long nextId() {
        long timestamp = timeGen();
        if (timestamp < lastTimestamp) {
            log.error("Clock moved backwards. Refusing to generate id for {} milliseconds", lastTimestamp - timestamp);
            throw new RuntimeException(String.format("Clock moved backwards. Refusing to generate id for %d milliseconds", lastTimestamp - timestamp));
        }
        if (lastTimestamp == timestamp) {
            sequence = (sequence + 1) & sequenceMask;
            if (sequence == 0) {
                timestamp = tilNextMillis(lastTimestamp);
            }
        } else {
            sequence = 0L;
        }
        lastTimestamp = timestamp;
        return ((timestamp - twepoch) << timestampLeftShift)
                | (datacenterId << datacenterIdShift)
                | (workerId << workerIdShift)
                | sequence;
    }

    protected long tilNextMillis(long lastTimestamp) {
        long timestamp = timeGen();
        while (timestamp <= lastTimestamp) {
            timestamp = timeGen();
        }
        return timestamp;
    }

    protected long timeGen() {
        return System.currentTimeMillis();
    }
}